package school.xauat.现代密码学.非对称加密;

import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author ：zsy
 * @date ：Created 2021/6/17 22:56
 * @description：RSA算法
 */
public class RSADemo {
    public static void main(String[] args) throws Exception {
        String input = "计算机网络安全";
        // 加密算法
        String algorithm = "RSA";
        generateKeyToFile(algorithm, "a.pub", "a.pri");
        String encrypted = encryptRSA(algorithm, "a.pub", input);
        System.out.println("公钥加密后：" + encrypted);
        String original = decryptRSA(algorithm, "a.pri", encrypted);
        System.out.println("私钥解密后：" + original);
    }


    /**
     * 生成公钥和私钥并保存文件
     * @param algorithm
     * @param pubPath
     * @param priPath
     * @throws Exception
     */
    public static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws  Exception{
        //获取密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        //获取密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //获取公钥
        PublicKey publicKey = keyPair.getPublic();
        //获取密钥
        PrivateKey privateKey = keyPair.getPrivate();
        //获取密钥字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();
        //进行Base编码
        String publicKeyString = Base64.encode(publicKeyEncoded);
        String privateKeyString = Base64.encode(privateKeyEncoded);
        //System.out.println("私钥：" + privateKeyString);
        //持久化文件
        FileUtils.write(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
        FileUtils.write(new File(priPath), privateKeyString, Charset.forName("UTF-8"));
    }

    /**
     * 获取文件中的公钥和私钥
     * @param algorithm
     * @param path
     * @return
     * @throws Exception
     */
    public static Key getKey(String algorithm, String path) throws Exception {
        // 将文件内容转为字符串
        String keyString = FileUtils.readFileToString(new File(path), Charset.defaultCharset());
        // 获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // 构建密钥规范 进行Base64解码
        EncodedKeySpec spec;
        if (path.contains("pub")) {
            spec = new X509EncodedKeySpec(Base64.decode(keyString));
        } else {
            spec = new PKCS8EncodedKeySpec(Base64.decode(keyString));
        }
        // 生成密钥
        return path.contains("pub") ?
                keyFactory.generatePublic(spec) : keyFactory.generatePrivate(spec);
    }

    /**
     * 使用公钥加密
     * @param algorithm
     * @param pubPath
     * @param input
     * @return
     * @throws Exception
     */
    private static String encryptRSA(String algorithm, String pubPath, String input) throws Exception {
        //获取公钥
        PublicKey publicKey = (PublicKey) getKey(algorithm, pubPath);
        //System.out.println(Base64.encode(publicKey.getEncoded()));
        //从文件中获取公钥
        String publicKeyString = FileUtils.readFileToString(new File(pubPath), Charset.forName("UTF-8"));
        byte[] keyBytes = Base64.decode(publicKeyString.getBytes());
        //获取加密对象
        Cipher cipher = Cipher.getInstance(algorithm);
        //初始化加密对象
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        //加密
        byte[] bytes = cipher.doFinal(input.getBytes());
        return Base64.encode(bytes);
    }

    /**
     * 使用私钥解密
     * @param algorithm
     * @param priPath
     * @param encrypted
     * @return
     * @throws Exception
     */
    private static String decryptRSA(String algorithm, String priPath, String encrypted) throws Exception{
        //获取私钥
        PrivateKey privateKey = (PrivateKey) getKey(algorithm, priPath);
        //System.out.println("文件获取私钥：" + Base64.encode(privateKey.getEncoded()));
        //获取加密对象
        Cipher cipher = Cipher.getInstance(algorithm);
        //初始化加密对象
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        //解密
        byte[] bytes = cipher.doFinal(Base64.decode(encrypted.getBytes()));

        return new String(bytes);
    }


}